package storage.multibuffer;

import engine.query.Plan;
import engine.query.Scan;
import engine.query.UpdateScan;
import server.starDB;
import storage.record.Schema;
import storage.record.TableInfo;
import storage.tx.Transaction;
import materialize.MaterializePlan;
import materialize.TempTable;

public class MultiBufferProductPlan implements Plan{

	private Plan lhs;
	private Plan rhs;
	private Transaction tx;
	private Schema schema = new Schema();
	
	public MultiBufferProductPlan(Plan lhs, Plan rhs, Transaction tx) {
		this.lhs = lhs;
		this.rhs = rhs;
		this.tx = tx;
		schema.addAll(lhs.schema());
		schema.addAll(rhs.schema());
	}
	@Override
	public int blocksAccessed() {
		// TODO Auto-generated method stub
		int avail = starDB.bufferMgr().available();
		int size = new MaterializePlan(rhs, tx).blocksAccessed();
		int numchunks = size / avail;
		return rhs.blocksAccessed() + (lhs.blocksAccessed() * numchunks);
	}

	@Override
	public int distinctValues(String fieldname) {
		// TODO Auto-generated method stub
		if(lhs.schema().hasField(fieldname)) {
			return lhs.distinctValues(fieldname);
		}
		return rhs.distinctValues(fieldname);
	}

	private TempTable copyRecordsFrom(Plan p)  {
		Scan sn = p.open();
		Schema sa = p.schema();
		TempTable tt = new TempTable(sa, tx);
		UpdateScan us = (UpdateScan)tt.open();
		while(sn.next()) {
			us.insert();
			for(String s : sa.fields()) {
				us.setVal(s, sn.getVal(s));
			}
		}
		sn.close();
		us.close();
		return tt;
	}
	@Override
	public Scan open(){
		// TODO Auto-generated method stub
		TempTable tt = copyRecordsFrom(rhs);
		TableInfo ti = tt.getTableInfo();
		Scan leftscan = lhs.open();
		return new MultiBufferProductScan(leftscan, ti, tx);
	}

	@Override
	public int recordsOutput() {
		// TODO Auto-generated method stub
		return lhs.recordsOutput() * rhs.recordsOutput();
	}

	@Override
	public Schema schema() {
		// TODO Auto-generated method stub
		return schema;
	}

	
}